﻿// ------------------------------------------------------------------------
// 版权信息
// 版权归重庆虫儿飞科技有限公司所有。
// 所有权利保留。
// 官方网站：https://netokit.com
// 许可证信息
// Neto.Kit 项目主要遵循 MIT 许可证和 Apache 许可证（版本 2.0）进行分发和使用。
// 许可证的完整文本可以在源代码树根目录中的 LICENSE-APACHE 和 LICENSE-MIT 文件中找到。
// 
// 使用条款
// 使用本代码应遵守相关法律法规和许可证的要求。
// 
// 免责声明
// 对于因使用本代码而产生的任何直接、间接、偶然、特殊或后果性损害，我们不承担任何责任。
// 
// 其他重要信息
// Neto.Kit 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。
// 有关 Neto.Kit 项目的其他详细信息，请参阅位于源代码树根目录中的 COPYRIGHT 和 DISCLAIMER 文件。
// 
// 更多信息
// 请访问 https://netokit.com 获取更多关于 Neto.Kit 项目的许可证和版权信息。
// ------------------------------------------------------------------------

#region

using NpgsqlTypes;
using Serilog;
using Serilog.Events;
using Serilog.Sinks.MSSqlServer;
using Serilog.Sinks.PostgreSQL;
using Serilog.Sinks.PostgreSQL.ColumnWriters;
using System.Globalization;
using ColumnOptions = Serilog.Sinks.MSSqlServer.ColumnOptions;
using ILogger = Serilog.ILogger;

#endregion

namespace Neto.Logging;

/// <summary>
///     Serilog拓展
/// </summary>
public static class SerilogX
{
    private static string DirectoryTrim(this string path)
    {
        return path.Trim('\\').Trim('/');
    }

    /// <summary>
    ///     获取Serilog 日志配置选项
    /// </summary>
    /// <returns></returns>
    private static SerilogConfigOptions GetSerilogOptions()
    {
        var serilogConfigOptions = AppX.GetConfig<SerilogConfigOptions>();
        serilogConfigOptions ??= new SerilogConfigOptions();
        serilogConfigOptions.File ??= new SerilogFile();
        serilogConfigOptions.Console ??= new SerilogConsole();
        serilogConfigOptions.SqlServer ??= new SerilogSQlServer();
        serilogConfigOptions.PostgreSQL ??= new SerilogPostgreSQL();
        return serilogConfigOptions;
    }

    #region Serilog  日志

    /// <summary>
    ///     日志输出模板
    /// </summary>
    public static readonly string SerilogOutputTemplate =
        "{NewLine}Date：{Timestamp:yyyy-MM-dd HH:mm:ss.fff} LogLevel：{Level}{NewLine}Message：{Message}{Properties:j}{NewLine}{NewLine}{Exception}" +
        new string('-', 50);

    /// <summary>
    ///     日志对象集合
    /// </summary>
    private static readonly ConcurrentDictionary<string, SeriLogCacheItem<ILogger>> Loggers = new();

    /// <summary>
    ///     获取 Serilog Logger
    /// </summary>
    /// <param name="logFloderName">日志文件夹名称</param>
    /// <param name="filename">文件名</param>
    /// <param name="minLogEventLevel">最低日志等级，默认Debug</param>
    /// <param name="rollingInterval">滚动间隔：日志将滚动到新文件的间隔</param>
    /// <param name="retainedFileCountLimit">保留的最大日志文件数，包括当前</param>
    /// <param name="flushToDiskInterval">TimeSpan 不为null，将定期在指定的时间执行完整磁盘刷新间隔。</param>
    /// <param name="buffered">指示是否可以缓存到输出文件。默认值 false</param>
    /// <param name="shared">允许多个进程共享日志文件。默认值为false</param>
    /// <param name="fileSizeLimitBytes">文件大小限制字节：允许日志文件访问的近似最大大小（以字节为单位）成长。对于不受限制的增长，传递null。默认值为1GB。避免写作部分事件，限制内的最后一个事件将全部写入偶数如果超过限制</param>
    /// <param name="outputTemplate">日志输出模板</param>
    /// <returns></returns>
    public static ILogger GetLogger(
        string logFloderName = "default", //日志文件夹名称
        string filename = "",
        LogEventLevel? minLogEventLevel = null, //最低日志等级，默认Debug
        RollingInterval? rollingInterval = null, //滚动间隔：日志将滚动到新文件的间隔
        int? retainedFileCountLimit = null, //保留的最大日志文件数，包括当前
        TimeSpan? flushToDiskInterval = null, //TimeSpan 不为null，将定期在指定的时间执行完整磁盘刷新间隔。
        bool buffered = false, //指示是否可以缓存到输出文件。默认值 false
        bool shared = false, //允许多个进程共享日志文件。默认值为false
        long? fileSizeLimitBytes =
            1073741824L, //文件大小限制字节：允许日志文件访问的近似最大大小（以字节为单位）成长。对于不受限制的增长，传递null。默认值为1GB。避免写作部分事件，限制内的最后一个事件将全部写入偶数如果超过限制
        string outputTemplate = ""
    )
    {
        var serilogConfigOptions = GetSerilogOptions();

        if (serilogConfigOptions.File == null) return GetLoggerByOptions(logFloderName, filename, serilogConfigOptions);
        serilogConfigOptions.File.MinLogEventLevel = minLogEventLevel.HasValue
            ? minLogEventLevel.Value
            : serilogConfigOptions.File.MinLogEventLevel;
        serilogConfigOptions.File.RollingInterval =
            rollingInterval ?? serilogConfigOptions.File.RollingInterval;
        serilogConfigOptions.File.RetainedFileCountLimit = retainedFileCountLimit;
        serilogConfigOptions.File.FlushToDiskInterval = flushToDiskInterval;
        serilogConfigOptions.File.Buffered = buffered;
        serilogConfigOptions.File.Shared = shared;
        serilogConfigOptions.File.FileSizeLimitBytes = fileSizeLimitBytes;
        serilogConfigOptions.File.OutputTemplate = outputTemplate;

        return GetLoggerByOptions(logFloderName, filename, serilogConfigOptions);
    }

    /// <summary>
    ///     获取 Serilog Logger
    /// </summary>
    /// <param name="logFloderName">日志文件夹名称</param>
    /// <param name="filename">文件名</param>
    /// <param name="serilogConfigOptions">Serilog选项配置</param>
    /// <returns></returns>
    public static ILogger GetLoggerByOptions(
        string logFloderName = "default", //日志文件夹名称
        string filename = "",
        SerilogConfigOptions? serilogConfigOptions = null)
    {
        serilogConfigOptions ??= GetSerilogOptions();

        //判断日志文件夹设置是否为空，如果为空，设置一个默认文件夹
        if (string.IsNullOrWhiteSpace(logFloderName))
            logFloderName = "default";
        else
            logFloderName = logFloderName.DirectoryTrim();
        logFloderName = logFloderName.ToOsDirectory();
        //对自定义文件名进行处理，去除末尾的 反斜杠字符
        if (!string.IsNullOrWhiteSpace(filename)) filename = filename.DirectoryTrim();
        //判断缓存的 ILogger 是否已存在，如果改以存在从字典集合直接取出使用，不在重新创建
        SeriLogCacheItem<ILogger> serilogCacheItem = null;

        //是否从缓存中取出Logger对象
        var isGetCacheLogger = false;
        //if (Loggers.ContainsKey(logFloderName))
        //{
        var state = Loggers.TryGetValue(logFloderName, out serilogCacheItem);
        if (state)
        {
            if (serilogCacheItem.Date == $"{DateTimeOffset.Now:yyyy-MM-dd}")
                isGetCacheLogger = true;
            else
            {
                //移除旧的Logger对象
                var removestate = Loggers.TryRemove(logFloderName, out var oldlogger);
            }
        }


        //}
        if (isGetCacheLogger == false)
        {
            serilogCacheItem = new SeriLogCacheItem<ILogger>();
            serilogCacheItem.Logger = new LoggerConfiguration()
                .SetMinimumLevel(serilogConfigOptions.File.MinLogEventLevel)
                .SetWriteTo(
                    serilogConfigOptions
                    , logFloderName //日志文件夹名称
                    , filename)
                .CreateLogger();

            Loggers.TryAdd(logFloderName, serilogCacheItem);

            // 每天首次创建logger时执行清理
            DeleteFloder(serilogConfigOptions, logFloderName);
        }

        if (serilogCacheItem == null) serilogCacheItem.Logger = Log.Logger;
        return serilogCacheItem.Logger;
    }

    /// <summary>
    ///     设置日志输出
    /// </summary>
    /// <param name="loggerConfiguration"></param>
    /// <param name="serilogConfigOptions"></param>
    /// <param name="logFloderName"></param>
    /// <param name="filename"></param>
    /// <returns></returns>
    private static LoggerConfiguration SetWriteTo(this LoggerConfiguration loggerConfiguration
        , SerilogConfigOptions serilogConfigOptions, // string path,
        string logFloderName = "", //日志文件夹名称
        string filename = "logs")
    {
        //日志是否输出到控制台
        if (serilogConfigOptions.Console is { IsEnable: true })
            loggerConfiguration.WriteTo.Console(outputTemplate: serilogConfigOptions.Console.OutputTemplate);
        //如果传入的日志模板为空，则使用默认的日志模板
        if (string.IsNullOrWhiteSpace(serilogConfigOptions.File.OutputTemplate))
            serilogConfigOptions.File.OutputTemplate = SerilogOutputTemplate;

        //日志是否写入到文件
        if (serilogConfigOptions.File.IsEnable)
            foreach (LogEventLevel logEventLevel in Enum.GetValues(typeof(LogEventLevel)))
                loggerConfiguration.WriteTo.Logger(lg => lg.Filter.ByIncludingOnly(p => p.Level == logEventLevel)
                    .WriteTo.File(
                        LogFilePath(serilogConfigOptions, logFloderName, logEventLevel, filename),
                        rollingInterval: serilogConfigOptions.File.RollingInterval,
                        outputTemplate: serilogConfigOptions.File.OutputTemplate,
                        rollOnFileSizeLimit: serilogConfigOptions.File.RollOnFileSizeLimit,
                        fileSizeLimitBytes: serilogConfigOptions.File.FileSizeLimitBytes,
                        retainedFileCountLimit: serilogConfigOptions.File.RetainedFileCountLimit,
                        flushToDiskInterval: serilogConfigOptions.File.FlushToDiskInterval,
                        shared: serilogConfigOptions.File.Shared,
                        buffered: serilogConfigOptions.File.Buffered
                    ));
        loggerConfiguration.SetSqlServer(serilogConfigOptions);
        loggerConfiguration.SetPostgreSql(serilogConfigOptions);

        return loggerConfiguration;
    }

    /// <summary>
    ///     设置SQL Server
    /// </summary>
    /// <param name="loggerConfiguration"></param>
    /// <param name="serilogConfigOptions"></param>
    /// <returns></returns>
    private static LoggerConfiguration SetSqlServer(this LoggerConfiguration loggerConfiguration,
        SerilogConfigOptions serilogConfigOptions)
    {
        //如果没有配置SqlServer,则直接返回
        if (serilogConfigOptions.SqlServer == null) return loggerConfiguration;
        if (serilogConfigOptions.SqlServer.IsEnable == false) return loggerConfiguration;
        //var columnOpts = new ColumnOptions();
        //columnOpts.Store.Remove(StandardColumn.Properties);
        //columnOpts.Store.Add(StandardColumn.LogEvent);
        //columnOpts.LogEvent.DataLength = 2048;
        //columnOpts.PrimaryKey = configOptions.TimeStamp;
        //columnOpts.TimeStamp.NonClusteredIndex = true;
        var columnOptions = new ColumnOptions();

        // 控制日志事件发送到SQL Server的频率。
        var isPeriod = TimeSpan.TryParse(serilogConfigOptions.SqlServer.Period, out var
            timeSpan);
        if (isPeriod == false) timeSpan = TimeSpan.FromSeconds(5);

        //选项
        var sinkOpts = new MSSqlServerSinkOptions
        {
            TableName = $"{serilogConfigOptions.SqlServer.TableName ?? "Logs"}-{DateTimeOffset.Now:yyyyMMdd}",
            BatchPostingLimit = serilogConfigOptions.SqlServer.BatchPostingLimit,
            BatchPeriod = timeSpan, //执行时间间隔
            AutoCreateSqlTable = serilogConfigOptions.SqlServer.AutoCreateSqlTable, // 是否自动创建日志表
            SchemaName = serilogConfigOptions.SqlServer.SchemaName, // 数据库名称
            AutoCreateSqlDatabase = serilogConfigOptions.SqlServer.AutoCreateSqlDatabase // 是否需要自动创建数据库
        };
        //写入到数据库
        loggerConfiguration.WriteTo.MSSqlServer(
            serilogConfigOptions.SqlServer.ConnectionString, //连接字符串
            sinkOpts,
            // tableName: tableName,
            //columnOptions: columnOptions,
            // batchPostingLimit: batchPostingLimit,//批量插入数据库条数
            //period: TimeSpan.FromSeconds(5),//执行时间间隔
            restrictedToMinimumLevel: serilogConfigOptions.SqlServer.RestrictedToMinimumLevel // 限制记录到日志表的最低日志级别
            //autoCreateSqlTable: true
        );

        return loggerConfiguration;
    }

    /// <summary>
    ///     设置PostgreSQL
    /// </summary>
    /// <param name="loggerConfiguration"></param>
    /// <param name="serilogConfigOptions"></param>
    /// <returns></returns>
    private static LoggerConfiguration SetPostgreSql(this LoggerConfiguration loggerConfiguration,
        SerilogConfigOptions serilogConfigOptions)
    {
        //如果没有配置PostgreSQL,则直接返回
        if (serilogConfigOptions.PostgreSQL == null) return loggerConfiguration;
        if (serilogConfigOptions.PostgreSQL.IsEnable == false) return loggerConfiguration;
        //var columnOpts = new ColumnOptions();
        //columnOpts.Store.Remove(StandardColumn.Properties);
        //columnOpts.Store.Add(StandardColumn.LogEvent);
        //columnOpts.LogEvent.DataLength = 2048;
        //columnOpts.PrimaryKey = configOptions.TimeStamp;
        //columnOpts.TimeStamp.NonClusteredIndex = true;
        //var columnOptions = new Serilog.Sinks.MSSql
        //连接字符串
        //var connectionString = App.Configuration["Serilog:Customer:PostgreSQL:ConnectionString"];
        //表名
        //var tableName = App.Configuration["Serilog:Customer:PostgreSQL:TableName"] ?? "SeriLogs";
        //loggerConfiguration.WriteTo.PostgreSQL(connectionString, tableName
        var tableName = $"{serilogConfigOptions.PostgreSQL.TableName ?? "Logs"}-{DateTimeOffset.Now:yyyyMMdd}";
        IDictionary<string, ColumnWriterBase> columnWriters = new Dictionary<string, ColumnWriterBase>
        {
            { "message", new RenderedMessageColumnWriter(NpgsqlDbType.Text) },
            { "message_template", new MessageTemplateColumnWriter(NpgsqlDbType.Text) },
            { "level", new LevelColumnWriter(true, NpgsqlDbType.Varchar) },
            { "raise_date", new TimestampColumnWriter(NpgsqlDbType.TimestampTz) },
            { "exception", new ExceptionColumnWriter(NpgsqlDbType.Text) },
            { "properties", new LogEventSerializedColumnWriter(NpgsqlDbType.Jsonb) },
            { "props_test", new PropertiesColumnWriter(NpgsqlDbType.Jsonb) },
            {
                "machine_name",
                new SinglePropertyColumnWriter("MachineName", PropertyWriteMethod.ToString, NpgsqlDbType.Text, "l")
            }
        };

        // 控制日志事件发送到SQL Server的频率。
        var isPeriod = TimeSpan.TryParse(serilogConfigOptions.PostgreSQL.Period, out var
            timeSpan);
        if (isPeriod == false) timeSpan = TimeSpan.FromSeconds(5);

        loggerConfiguration.WriteTo.PostgreSQL(
            serilogConfigOptions.PostgreSQL.ConnectionString,
            tableName, // 存储日志的表名
            columnWriters,
            serilogConfigOptions.PostgreSQL.RestrictedToMinimumLevel, // 限制记录到日志表的最低日志级别
            needAutoCreateTable: serilogConfigOptions.PostgreSQL.NeedAutoCreateTable, //是否需要自动创建日志表
            batchSizeLimit: serilogConfigOptions.PostgreSQL.BatchPostingLimit, //批量插入数据库条数
            schemaName: serilogConfigOptions.PostgreSQL.SchemaName, //数据库名
            needAutoCreateSchema: serilogConfigOptions.PostgreSQL.NeedAutoCreateSchema //是否需要自动创建数据库
        );

        return loggerConfiguration;
    }

    private static LoggerConfiguration SetMinimumLevel(this LoggerConfiguration loggerConfiguration,
        LogEventLevel minLevel)
    {
        switch (minLevel)
        {
            case LogEventLevel.Verbose: //冗余的
                return loggerConfiguration.MinimumLevel.Verbose();

            case LogEventLevel.Debug: //调试
                return loggerConfiguration.MinimumLevel.Debug();

            case LogEventLevel.Information: //信息
                return loggerConfiguration.MinimumLevel.Information();

            case LogEventLevel.Warning: //警告
                return loggerConfiguration.MinimumLevel.Warning();

            case LogEventLevel.Error: //错误
                return loggerConfiguration.MinimumLevel.Error();

            case LogEventLevel.Fatal: //致命
                return loggerConfiguration.MinimumLevel.Fatal();
        }

        return loggerConfiguration.MinimumLevel.Debug();
    }

    private static string LogFilePath(SerilogConfigOptions? serilogConfigOptions, string logFloderName,
        LogEventLevel loglevel,
        string filename = "")
    {
        if (serilogConfigOptions == null) serilogConfigOptions = GetSerilogOptions();
        if (string.IsNullOrWhiteSpace(filename)) filename = $"{loglevel:G}";
        if (serilogConfigOptions.File is { IsCreateDateFileFloder: true })
        {
            var date = DateTime.Now.ToString("yyyy-MM-dd"); //按时间创建文件夹
            return $"logs\\{logFloderName}\\{date}\\{filename}_.txt".ToOsDirectory();
        }

        return $"logs\\{logFloderName}\\{filename}_.txt".ToOsDirectory();
    }

    /// <summary>
    ///     获取日志文件全路径
    /// </summary>
    /// <param name="serilogConfigOptions"></param>
    /// <param name="logFloderName"></param>
    /// <returns></returns>
    private static string GetLogFullFileFloderPath(SerilogConfigOptions serilogConfigOptions, string logFloderName)
    {
        // 使用Path.Combine替代字符串拼接
        return Path.Combine(
            App.HostEnvironment.ContentRootPath,
            "logs",
            logFloderName
        ).ToOsDirectory();
    }

    /// <summary>
    ///     设置Serilog 默认日志配置
    /// </summary>
    /// <returns></returns>
    public static void SetDefaultConfiguration(LoggerConfiguration config)
    {
        var serilogConfigOptions = GetSerilogOptions();
        var date = DateTime.Now.ToString("yyyy-MM-dd"); //按时间创建文件夹
        config.WriteTo.Console(outputTemplate: SerilogOutputTemplate)
            .WriteTo.File($"logs\\all\\{date}\\log_.txt".ToOsDirectory(),
                rollingInterval: RollingInterval.Day,
                rollOnFileSizeLimit: true,
                fileSizeLimitBytes: 20971520,
                shared: true
            );
        foreach (LogEventLevel logEventLevel in Enum.GetValues(typeof(LogEventLevel)))
            config.WriteTo.Logger(lg => lg.Filter.ByIncludingOnly(p => p.Level == logEventLevel)
                .WriteTo.File(LogFilePath(serilogConfigOptions, "all", logEventLevel),
                    rollingInterval: RollingInterval.Day,
                    outputTemplate: SerilogOutputTemplate,
                    rollOnFileSizeLimit: true,
                    fileSizeLimitBytes: 20971520,
                    shared: true
                ));
    }

    /// <summary>
    ///     判断是否是日期格式
    /// </summary>
    /// <param name="input"></param>
    /// <param name="date"></param>
    /// <returns></returns>
    private static bool TryParseDateFromString(string input, out DateTime date)
    {
        // 支持 yyyy-MM-dd 和 yyyyMMdd 两种格式
        if (DateTime.TryParseExact(input, "yyyy-MM-dd", null, DateTimeStyles.None, out date))
            return true;

        return DateTime.TryParseExact(input, "yyyyMMdd", null, DateTimeStyles.None, out date);
    }

    /// <summary>
    ///     删除日志
    ///     注意：不影响Serilog的删除日志逻辑
    /// </summary>
    /// <param name="serilogConfigOptions"></param>
    /// <param name="logFloderName"></param>
    private static void DeleteFloder(SerilogConfigOptions serilogConfigOptions, string logFloderName)
    {
        try
        {
            // 如果配置了不删除日志，则不执行下面的代码
            if (serilogConfigOptions.File is { IsCustomerDeletedLog: false }) return;
            //如果不是按时间创建文件夹，则不执行下面的代码，因为Serilog会自动删除过期的日志文件
            if (serilogConfigOptions.File is { IsCreateDateFileFloder: true }) return;
            //如果保留最大日志文件夹数小于等于0，则不删除
            if (serilogConfigOptions.File != null &&
                (serilogConfigOptions.File.RetainedFloderCountLimit.HasValue == false ||
                 serilogConfigOptions.File.RetainedFloderCountLimit.Value <= 0)) return;


            //获取程序更目录，要分别注意是web还是host
            var directory = GetLogFullFileFloderPath(serilogConfigOptions, logFloderName);
            //var directory = Path.GetDirectoryName(logPath);

            // 新增目录存在性检查
            Console.WriteLine($"Checking directory: {directory}");
            if (!Directory.Exists(directory))
            {
                Console.WriteLine($"Directory not exist: {directory}");
                return;
            }

            // 获取文件保留天数
            var fileRetentionDays = Math.Max(1, serilogConfigOptions?.File?.RetainedFileCountLimit ?? 10);
            var fileCutoffDate = DateTime.Today.AddDays(-fileRetentionDays);
            // 保留文件夹天数
            var floderRetentionDays = Math.Max(1, serilogConfigOptions?.File?.RetainedFloderCountLimit ?? 7);
            var floderCutoffDate = DateTime.Today.AddDays(-floderRetentionDays);


            // 处理日期格式文件夹
            var directories = Directory.GetDirectories(directory)
                .Select(d => new { Path = d, Name = Path.GetFileName(d) })
                .Where(d => TryParseDateFromString(d.Name, out var date))
                .Select(d => new
                {
                    d.Path,
                    Date = DateTime.ParseExact(d.Name, ["yyyy-MM-dd", "yyyyMMdd"], null, DateTimeStyles.None)
                });

            // 处理日期格式文件（适配多种命名规则）
            var files = Directory.GetFiles(directory, "*.*") // 获取所有带扩展名的文件
                .Where(f =>
                {
                    var extension = Path.GetExtension(f).ToLower();
                    return extension is ".txt" or ".log"; // 仅选择 .txt 和 .log 文件
                })
                .Select(f => new
                {
                    Path = f,
                    FileName = Path.GetFileNameWithoutExtension(f),
                    Parts = Path.GetFileNameWithoutExtension(f).Split('_', '-') // 同时支持下划线和短横线分隔符
                })
                .Where(f => f.Parts.Length >= 2)
                .Select(f => new
                {
                    f.Path,
                    DateString = f.Parts[^1], // 取最后一个元素作为日期部分
                    f.Parts
                })
                .Where(f => TryParseDateFromString(f.DateString, out _))
                .Select(f => new
                {
                    f.Path,
                    Date = DateTime.ParseExact(
                        f.DateString,
                        ["yyyyMMdd", "yyyy-MM-dd", "yyyy_MM_dd"],
                        CultureInfo.InvariantCulture
                    )
                });

            // 合并需要删除的项目
            var itemsToDelete = directories
                .Select(d => new { d.Path, IsDirectory = true, d.Date })
                .Concat(files.Select(f => new { f.Path, IsDirectory = false, f.Date }))
                .Where(item =>
                    (item.IsDirectory && item.Date < floderCutoffDate) ||
                    (!item.IsDirectory && item.Date < fileCutoffDate)
                )
                .OrderBy(item => item.Date)
                .ToList();

            // 执行删除
            foreach (var item in itemsToDelete)
                try
                {
                    if (item.IsDirectory)
                        Directory.Delete(item.Path, true); // 递归删除文件夹
                    else
                        File.Delete(item.Path);

                    Console.WriteLine($"Deleted: {item.Path}");
                }
                catch (Exception ex)
                {
                    Console.WriteLine($"Error deleting {item.Path}: {ex.Message}");
                    // 可记录到日志系统
                }
        }
        catch (Exception e)
        {
            Console.WriteLine($"DeleteFloder : {e.Message}");
            //throw;
        }
    }

    #endregion Serilog  日志
}